from vquant.order import Order
from vquant.position import Position
from vquant.snapshot import Snapshot


class BackBroker(object):
    def __init__(self, cerebro):
        self.cerebro = cerebro
        self.cash = 1000000
        self.commission = 0
        self.fund = self.cash
        self.commission_rate = 0
        self.leverage = 1
        self.quantity_multiple = 100
        self.order = Order()
        self.position = Position()
        self.snapshot = Snapshot()

    @property
    def equity(self):
        return self.cash + self.profit

    @property
    def profit(self):
        return self.position.query(quantity=dict(ne=0)).profit.sum()

    @property
    def frozen(self):
        return self.position.query(quantity=dict(ne=0)).margin.sum()

    @property
    def available(self):
        return self.cash - self.frozen

    def set_cash(self, value):
        if self.cash == self.fund:
            self.cash, self.fund = (value, value)

    def get_margin(self, order):
        margin = 0
        holdings = order.quantity if order.side == self.order.Buy else -order.quantity
        positions = self.position.query(symbol=dict(eq=order.symbol))
        if positions.shape[0]:
            position = positions.iloc[0]
            holdings = position.quantity + holdings
            margin = position.margin
        return abs(holdings) * order.price * self.quantity_multiple / self.leverage - margin

    def settle_order(self, order):
        order.commission = order.price * order.quantity * self.quantity_multiple * self.commission_rate
        if self.available < order.commission + self.get_margin(order):
            order.state = self.order.Rejected
        else:
            position, order.profit = self.position.add(
                order.datetime, order.symbol, order.price,
                order.quantity if order.side == self.order.Buy else -order.quantity,
                self.leverage, self.quantity_multiple
            )
            self.cash = self.cash - order.commission + order.profit
            self.commission = self.commission + order.commission
            order.state = self.order.Filled
        self.order.update(order.to_dict(), id=dict(eq=order.id))
        return order

    def create_order(self, symbol, side, price, quantity):
        order = self.order.insert(
            id=self.order.id(), datetime=self.cerebro.datafeed.datetime,
            symbol=symbol, side=side, price=price, quantity=quantity,
            state=self.order.Created
        ).copy()
        return self.settle_order(order)

    def on_replace_position(self, dataframe):
        positions = self.position.query(
            symbol=dict(isin=dataframe.symbol.values),
            quantity=dict(ne=0)
        )
        for _, position in positions.iterrows():
            tick = dataframe.loc[dataframe.symbol.eq(position.symbol)].iloc[0]
            self.position.replace(
                position, tick.close,
                self.quantity_multiple
            )
        self.snapshot.insert(
            datetime=self.cerebro.datafeed.datetime,
            value=self.equity
        )


__all__ = [BackBroker]
